#include "polynomial.h"

Polynomial::Polynomial(const Polynomial &p)
{
    coefficient = p.coefficient;
}

Polynomial &Polynomial::operator=(const Polynomial &p)
{
    if (this != &p)
    {
        coefficient = p.coefficient; // 进行深拷贝
    }
    return *this;
}

Polynomial &Polynomial::operator=(Polynomial &&p)
{
    if (this != &p)
    {
        coefficient = std::move(p.coefficient); // 使用移动语义
    }
    return *this;
}

Polynomial Polynomial::diff() const
{
    int n = this->coefficient.size();
    // 常数求导返回零
    if (n == 1)
    {
        return Polynomial(std::vector<double>(1, 0));
    }
    std::vector<double> v(n - 1);
    for (int i = 0; i < n - 1; ++i)
    {
        v[i] = this->coefficient[i + 1] * (i + 1); // 求导计算
    }
    return Polynomial(v);
}

Polynomial Polynomial::integral() const
{
    int n = this->coefficient.size();
    std::vector<double> v(n + 1);
    v[0] = 0.0;
    for (int i = 1; i < n + 1; ++i)
    {
        v[i] = this->coefficient[i - 1] / i; // 积分计算
    }
    return Polynomial(v);
}

double Polynomial::evaluate(double x) const
{
    double y = 0.0, pow = 1.0;
    for (int i = 0; i < this->coefficient.size(); ++i)
    {
        y += this->coefficient[i] * pow; // 多项式求值
        pow *= x;
    }
    return y;
}

inline void Polynomial::set_coef(std::vector<double> v)
{
    coefficient = v;
    check();
}

inline void Polynomial::set_coef(int degree, double value)
{
    coefficient[degree] = value;
    check();
}

inline std::vector<double> Polynomial::get_coef() const
{
    return coefficient;
}

inline int Polynomial::get_order() const
{
    return coefficient.size() - 1;
}

Polynomial Polynomial::operator+(const Polynomial &p) const
{
    int n = this->coefficient.size();
    int m = p.coefficient.size();
    int k = (n > m) ? n : m;
    std::vector<double> v(k, 0);
    for (int i = 0; i < k; i++)
    {
        if (i >= n)
        {
            v[i] = p.coefficient[i];
        }
        else if (i >= m)
        {
            v[i] = this->coefficient[i];
        }
        else
        {
            v[i] = this->coefficient[i] + p.coefficient[i]; // 多项式相加
        }
    }
    return Polynomial(v);
}

Polynomial Polynomial::operator+(double x) const
{
    std::vector<double> v(coefficient);
    v[0] += x;
    return Polynomial(v);
}

Polynomial Polynomial::operator-(const Polynomial &p) const
{
    int n = this->coefficient.size();
    int m = p.coefficient.size();
    int k = (n > m) ? n : m;
    std::vector<double> v(k, 0);
    for (int i = 0; i < k; i++)
    {
        if (i >= n)
        {
            v[i] = -p.coefficient[i];
        }
        else if (i >= m)
        {
            v[i] = this->coefficient[i];
        }
        else
        {
            v[i] = this->coefficient[i] - p.coefficient[i]; // 多项式相减
        }
    }
    return Polynomial(v);
}

Polynomial Polynomial::operator-(double x) const
{
    std::vector<double> v(coefficient);
    v[0] -= x;
    return Polynomial(v);
}

Polynomial Polynomial::operator*(const Polynomial &p) const
{
    int n = coefficient.size();
    int m = p.coefficient.size();
    std::vector<double> v(n + m - 1, 0);
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            v[i + j] += coefficient[i] * p.coefficient[j];
    return Polynomial(v);
}

Polynomial Polynomial::operator*(double x) const
{
    int n = coefficient.size();
    std::vector<double> v(n, 0);
    for (int i = 0; i < n; ++i)
    {
        v[i] = coefficient[i] * x;
    }
    return Polynomial(v);
}

Polynomial Polynomial::operator/(double x) const
{
    int n = coefficient.size();
    std::vector<double> v(n, 0);
    for (int i = 0; i < n; ++i)
    {
        v[i] = coefficient[i] / x;
    }
    return Polynomial(v);
}

Polynomial Polynomial::operator^(int x) const
{
    if (x < 0)
        throw;
    else if (x == 0)
        return Polynomial(std::vector<double>(1, 1.0));
    else if (x == 1)
        return (*this);
    else if (x % 2 == 1)
        return (((*this) * (*this)) ^ (x / 2)) * (*this);
    else
        return ((*this) * (*this)) ^ (x / 2);
}

void Polynomial::print() const
{
    for (int i = coefficient.size() - 1; i > 0; --i)
    {
        std::cout << coefficient[i] << "x^" << i << " + ";
    }
    std::cout << coefficient[0] << std::endl;
}

inline void Polynomial::check()
{
    // 确保非常数多项式最高次系数不为0
    while (coefficient.back() == 0.0 && coefficient.size() != 1)
        coefficient.pop_back();
    return;
}

Polynomial operator*(double x, const Polynomial &p)
{
    int n = p.coefficient.size();
    std::vector<double> v(n, 0);
    for (int i = 0; i < n; ++i)
    {
        v[i] = p.coefficient[i] * x;
    }
    return Polynomial(v);
}
